<?php

/**
 * 组装返回数据
 * @param $type 信息类别（login,notice,msg,logout 等用于区别返回的信息用在哪里）
 * @param $data 返回数据
 * @param int $code 返回状态码
 * @param string $msg 返回状态信息
 * @return string 转换的json数据
 */
function myResult($type, $data, $code=200, $msg='请求成功'){
    $result = [
        'code' => $code,
        'msg'  => $msg,
        'type' => $type,
        'data' => $data
    ];
    return json_encode($result);
}


$userTable = new Swoole\Table(1024);
$userTable->column('id', Swoole\Table::TYPE_INT);
$userTable->column('nickname', Swoole\Table::TYPE_STRING, 64);
$userTable->column('token', Swoole\Table::TYPE_STRING, 64);
$userTable->column('avatar', Swoole\Table::TYPE_STRING, 64);
$userTable->create();

$tokenTable = new Swoole\Table(1024);
$tokenTable->column('id', Swoole\Table::TYPE_INT);
$tokenTable->column('nickname', Swoole\Table::TYPE_STRING, 64);
$tokenTable->column('token', Swoole\Table::TYPE_STRING, 64);
$tokenTable->column('avatar', Swoole\Table::TYPE_STRING, 64);
$tokenTable->create();


//实例化swoole的websocket服务
$serv = new swoole_websocket_server('0.0.0.0',9501);
$serv->user = $userTable;
$serv->token = $tokenTable;

//监听websocket连接
$serv->on('open',function($ws,$request){
    
    //将连接信息保存起来( $request->fd 为连接id )
    $ws->user->set($request->fd, [
        'id' => $request->fd,
        'nickname' => '匿名用户'
    ]);
});

//监听websocket发送上来的信息
$serv->on('message',function($ws,$request){

    //获取当前连接的用户信息
    $user =  $ws->user->get($request->fd);

    //将用户发送上来的数据格式化成数组（客户端上传的json数据）
    $data = json_decode($request->data,true);

    //判断是否登录操作（模拟的用于绑定用户信息）
    if($data['a'] == 'login'){

        //组装用户信息
        $myUser = $user;
        $userInfo = $data['userInfo'];
        $myUser['token'] = $userInfo['token'];
        $myUser['nickname'] = $userInfo['nickname'];
        $myUser['avatar'] = $userInfo['avatar'];

        //将用户信息根据token保存起来
        $ws->token->set($myUser['token'], $myUser);

        //将用户信息根据连接id保存起来
        $ws->user->set($request->fd, $myUser);
        $msg = " {$myUser['nickname']} 加入聊天室 ";


        //获取当前所有用户信息
        $userlist = [];
        foreach ($ws->user as $toUser){
            $userlist[] = $toUser;
        }

        //将所有用户列表推送给客户端
        $ws->push($myUser['id'],myResult('userlist',$userlist));

        //将用户登录信息推送到所有在线客户端
        foreach ($ws->user as $toUser){
            //不用推送给自己
            if($toUser['id']!=$myUser['id']) {
                $ws->push($toUser['id'], myResult('login', ['msg' => $msg, 'userInfo' => $myUser]));
            }
        }

    }


    //客户端发送信息操作
    if($data['a'] == 'msg'){

        //获取客户端信息发送给谁 0表示 所有人
        $to_uid = $data['to_uid'];
        //客户端发送的消息
        $msg = $data['msg'];

        //获取当前用户信息
        $myUser = $ws->user->get($request->fd);
        //将信息推送给自己
        $ws->push($request->fd,myResult('msg',['msg'=>$msg,'nickname'=>$myUser['nickname'],'avatar'=>$myUser['avatar'],'add_time'=>date('Y-m-d H:i:s')]));

        if($to_uid){

            //获取全中的用户信息（发送给谁的信息）
            $toUser = $ws->token->get($to_uid);

            //将信息推送到指定用户客户端
            if($toUser['id']){
                $ws->push($toUser['id'],myResult('msg',['msg'=>$msg,'nickname'=>$myUser['nickname'],'avatar'=>$myUser['avatar'],'add_time'=>date('Y-m-d H:i:s')]));
            }

        }else{
            //将信息发送给所有在线客户端
            foreach ($ws->user as $toUser){
                //用户列表中排除自己
                if($toUser['id']!=$myUser['id']){
                    $ws->push($toUser['id'],myResult('msg',['msg'=>$msg,'nickname'=>$myUser['nickname'],'avatar'=>$myUser['avatar'],'add_time'=>date('Y-m-d H:i:s')]));
                }
            }

        }

    }

});

//监听websocket断开连接
$serv->on('close',function($ws,$ws_uid){

    $msg = "{$ws_uid} 关闭连接";

    //获取断开连接的用户信息
    $myUser = $ws->user->get($ws_uid);
    if($myUser['token']){
        $msg = $myUser['nickname'].'退出聊天室';

        //将断开连接的用户信息推送给所有在线客户端
        foreach ($ws->user as $toUser) {
            //用户列表中排除自己
            if ($toUser['id'] != $myUser['id']) {
                $ws->push($toUser['id'], myResult('logout', ['msg' => $msg, 'userInfo' => $myUser]));
            }

        }
        //将全局用户数组（token）中删除断开连接的用户
        $ws->token->del($myUser['token']);
    }

    //将全局用户数组（连接id）中删除断开连接的用户
    $ws->user->del($ws_uid);

});

//启动服务器
$serv->start();